﻿

namespace GettingStarted {
  using System;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Media;
  using Bling.DSL;
  using Bling.WPF;
  public class GettingStarted : Canvas {
    public GettingStarted() {
      var canvas = this.Bl();

      /*
The code used in this getting started example is located in the GettingStarted.cs file of the 
GettingStarted project in the release. We start of this example by creating a *thumb* and 
*label* on a *canvas*:
       */
      var thumb = new ThumbBl(canvas) {
        Background = Brushes.Red,
        CanDrag = true,
        RightBottom = canvas.Size,
        ZIndex = 1,
      };
      LabelBl label = new LabelBl(canvas) {
        Content = "Hello World: ".Bl() + thumb.CenterPosition,
        Font = { Size = 80, Weight = FontWeights.SemiBold, },
        CenterPosition = canvas.CenterSize,
      };
/*
The first statement creates a red *thumb* that can be dragged (_CanDrag = true_).  
The initial location of the *thumb* is in the right hand bottom corner of the *canvas*,
while its Z index is set to one.  The second statement creates a *label* whose content
is bound to "Hello World" prepended to the current location of the *thumb*.  By default,
assigments to properties in Bling are _contraints_ where the bound to property will change
as the bound-to expression changes.  In our example, the *label*'s content will change
to always reflect the location of the *thumb*, which you can experience this by moving the *thumb*.
Likewise, the center position of the *label* is bound to the center of its containing canvas. As the 
window that contains the canvas is resized, the label is repositioned so that it always remains in
the center. 

Constraints are ubiquitous and incredibly expressive in Bling. Consider another constraint:
 */
      label.RenderTransform.Rotate = (thumb.CenterPosition - label.CenterPosition).Angle.ToDegrees();

/*
This code rotates the *label* according to the position of the *thumb* with respect to the center of the *label*. 
A vector from the center of the *label* is first computed using subtraction, where the vector is then converted
into a radian angle (via _Angle_), which itself is turned into a degree angle (_ToDegrees_).  The result is that
the *label* rotates as the *thumb* is moved in a circle around its center.  This example demonstrates the power
of Bling constraints: properties can be bound to many kinds of expressions including those that operate over
angles.

The next piece of code demonstrates how a UI widget can easily undergo custom pixel shading: 
*/
      var thumbB = new ThumbBl(canvas) {
        Background = Brushes.Blue, LeftTop = new PointBl(0,0), CanDrag = true 
      };

      label.Effect.Custom = (input, uv) => {
        /*L1*/ var p = label.RenderTransform.Inverse.Transform(thumbB.CenterPosition - label.LeftTop);
        /*L2*/ var q = uv * label.Size;
        /*L3*/ var d = (p - q).Length;
        /*L4*/ d = 1 - (d / 500).Min(1);
        /*L5*/ var clr = (d).Lerp(Colors.Black, Colors.Blue);
        /*L6*/ return ColorBl.FromScRGB((input[uv].ScA).Min((1 - (d * d)).Max(.4)), clr.ScRGB);
      };
/*
We want to shade the *label* with respect to the position of *thumbB*. 
However, pixel shader effects are applied before render transforms, so we have to transform 
the position of *thumbB* with respect to *label*'s inverse transform, which happens on 
the first line of the shader (below _{"(input,uv) => {"}_). Since transforms are 
relative to the widgets they are applied, we also
subtract *label*'s left top position from *thumbB*'s center position. *uv* identifies the 
position of the pixel being shaded in term of a percentage rather than in pixels.  So that
we can compare *uv* to the position of *thumbB*, we multiple it by the size of the label 
(line two) and then we can find the distance between the two points (line three).  Line four
specifies that the circle we care about is 500 pixels in radius, which we then invert so
that closer distances are higher in value. Line five uses the result *d* to interpolate between
black and blue colors, which is then used on line six to create the color of the pixel with
some modifications to its alpha. 

The resulting pixel shader executes on the GPU with performance similar to a DirectX pixel shader,
and in fact, it is a DirectX pixel shader. Pixel shaders can refer to many UI objects and properties 
directly, such as positions, although there are limitations. For example, a pixel shader can refer
to a point property but not an enum property, and can rever to an image brush but not a solid color
brush (due to limitations enforced by WPF). 
 */
    }
    [STAThread]
    public static void Main(string[] args) {
      var win = new Window() { Title = "Getting Started", Content = new GettingStarted() };
      new Application().Run(win);
      return;
    }
  }
}
